/* JavaLog - package tracker 
 * 
 * Copyright (C) 2009  Allyson Lima, Diego Pedro, Victor Freire
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software 
 * Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this 
 * program.  If not, see <http://www.gnu.org/licenses/>.
 */

package br.edu.ufcg.ccc.javalog;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import br.edu.ufcg.ccc.javalog.Franchise;
import br.edu.ufcg.ccc.javalog.Headquarters;

/**
 * Main class.
 * @author Allyson Lima, Diego Pedro, Victor Freire
 * @version 11/10/09
 */
public class Main {
	private static final Scanner sc = new Scanner(System.in);
	private static final List<String> MENU_OPTIONS = new ArrayList<String>();
	
	private static final Headquarters headquarters = new Headquarters("Matriz", 
			new Address("Nordeste", "Paraiba", "Campina Grande", 
					    "Bodocongo", "59021666", "Aprigio Veloso", "666"), true);
	
	static 
	{
		MENU_OPTIONS.add("Adicionar franquia");
		MENU_OPTIONS.add("Ver franquia");
		MENU_OPTIONS.add("Modificar o nome de uma franquia");
		MENU_OPTIONS.add("Modificar o local de uma franquia");
		MENU_OPTIONS.add("Modificar dados do aeroporto de uma franquia");
		MENU_OPTIONS.add("Deletar franquia");
	}
	
	/**
	 * Get integer that is between the requested interval([a,b]) from the standard input.
	 * @param prompt request message
	 * @param min minimum value (inclusive)
	 * @param max max value(inclusive)
	 * @return valid integer
	 */
	private static int getInt(String prompt, int min, int max) {
		while(true) {
			System.out.printf(prompt);
			while(!sc.hasNextInt()) sc.next();
						
			int inteiro = sc.nextInt();
			if(min <= inteiro && inteiro <= max) return inteiro;
			System.err.printf("Número inválido! Precisa estar entre %d e %d.%n", min, max);
			
		}
	}
	
	/**
	 * Gets a valid string from the user.
	 * @param prompt request message
	 * @return valid and non-empty string
	 */
	private static String getString(String prompt) {
		System.out.printf(prompt);
		while(true) {
			
			while(!sc.hasNextLine()) sc.next();
			
			String txt = sc.nextLine();
			
			if(txt == null) {
				System.err.println("Texto inválido!");
				System.out.printf(prompt);
			}
			else if(txt.equals("")) continue;
			else return txt;
		}
	}
	
	/**
	 * Gets a boolean answer from the the standard input.
	 * @return boolean answer
	 */
	private static boolean getYesOrNo(String prompt) {
		final String answersPositive = "y;yes;sim;s;";
		final String answersNegative = "n;no;nao;não;";
		while(true) {
			String answer = getString(prompt);
			
			if(answersPositive.contains(answer + ";")) return true;
			else if(answersNegative.contains(answer + ";")) return false;
			
			System.err.println("Resposta inválida! Use s, n, sim ou não.");
		}
	}
	
	/**
	 * Gets a valid address from the standard input.
	 * @return valid address 
	 */
	private static Address getAddress() {
		while(true) {
			String region = getString("Região: ");
			String state = getString("Estado: ");
			String city = getString("Cidade: ");
			String district = getString("Bairro: ");
			String zipcode = getString("CEP: ");
			String street = getString("Endereço: ");
			String number = getString("Número: ");
			try {
				return new Address(region, state, city, district, zipcode, street, number);
			}
			catch(Exception e) {
				System.err.println("Endereço inválido!");
			}
		}
	}
	
	/**
	 * Gets a valid Franchise from the standard input.
	 * @return valid Franchise
	 */
	private static Franchise getFranchise() {
		while(true) {
			String name = getString("Nome: ");
			Address address = getAddress();
			boolean hasAirport = getYesOrNo("Tem aeroporto?(y/n): ");
			try {
				return new Franchise(name, address, hasAirport);
			}
			catch(Exception e) {
				System.err.println("Franquia inválida!");
			}
		}
	}
	
	/**
	 * Displays the text menu.
	 */
	private static void displayMenu() {
		System.out.printf("%nJavaLog - Rastreador de Pacotes by Allyson Lima, Diego Pedro and Victor Freire%n%n");
		
		for(int i = 0; i < MENU_OPTIONS.size(); ++i) {
			System.out.printf("%d. %s%n", i + 1, MENU_OPTIONS.get(i));
		}
		System.out.printf("0. Exit%n");
	}
	
	
	
	/**
	 * Main Entry point for JavaLog.
	 */
	public static void main(String[] args) {
		main_loop:
			while(true) {
				displayMenu();
				int cmd = getInt("%nSelecione uma opção: ", 0, MENU_OPTIONS.size());

				switch(cmd) {
				case 0:
					break main_loop;
					
				case 1:
					// See franchise
					if(!headquarters.addFranchise(getFranchise())) 
						System.out.println("Já existe uma franquia nesse local!");
					else
						System.out.println("Franquia adicionada com sucesso!");
					break;

				case 2:
					Franchise f2 = headquarters.getFranchise(getAddress());
					if(f2 != null) { 
						System.out.printf("Franquia encontrada: %n%n");
						System.out.println(f2);
					}
					else { 
						System.out.println("Não existe uma franquia nesse local!");
					}
					break;

				case 3:
					Franchise f3 = headquarters.getFranchise(getAddress());
					if(f3 != null) { 
						System.out.println("Franquia encontrada: %n%n");
						System.out.println(f3);
						System.out.println();
						try {
							f3.setName(getString("Digite o novo nome: "));
						} catch (Exception e) {
							assert false : "Unreachable, getString() always returns a valid string";
						}
						System.out.println("Franquia atualizada.");
					}
					else { 
						System.out.println("Não existe uma franquia nesse local!");
					}
					
					break;					
				case 4:
					Franchise f4 = headquarters.getFranchise(getAddress());
					if(f4 != null) { 
						System.out.println("Franquia encontrada: %n%n");
						System.out.println(f4);
						System.out.println();
						System.out.println("Digite o novo endereço. ");
						try {
							f4.setAddress(getAddress());
						} catch (Exception e) {
							assert false : "Unreachable, getAddress() always returns a valid address";
						}
						System.out.println("Franquia atualizada.");
					}
					else { 
						System.out.println("Não existe uma franquia nesse local!");
					}
					
					break;
				
				case 5:
					Franchise f5 = headquarters.getFranchise(getAddress());
					if(f5 != null) { 
						System.out.println("Franquia encontrada: %n%n");
						System.out.println(f5);
						f5.setHasAirport(getYesOrNo("Tem aeroporto?(y/n): "));
						System.out.println("Franquia atualizada.");
					}
					else { 
						System.out.println("Não existe uma franquia nesse local!");
					}

					break;
					
				case 6:
					if(headquarters.removeFranchise(getAddress()) != null)
						System.out.println("Franquia removida com sucesso!");
					else 
						System.out.println("Não existe uma franquia nesse local!");
					break;

				default:
					System.err.println("Opção não reconhecida!");
					break;
				}
			}

		System.out.printf("%nObrigado por usar JavaLog!%n");
	}
}

